home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / timed / master.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-12-23  |  12.1 KB  |  560 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. static char sccsid[] = "@(#)master.c    2.15 (Berkeley) 12/23/87";
  15. #endif /* not lint */
  16.  
  17. #include "globals.h"
  18. #include <protocols/timed.h>
  19. #include <sys/file.h>
  20. #include <setjmp.h>
  21. #include <utmp.h>
  22.  
  23. extern int machup;
  24. extern int measure_delta;
  25. extern jmp_buf jmpenv;
  26.  
  27. extern u_short sequence;
  28.  
  29. #ifdef MEASURE
  30. int header;
  31. FILE *fp = NULL;
  32. #endif
  33.  
  34. /*
  35.  * The main function of `master' is to periodically compute the differences 
  36.  * (deltas) between its clock and the clocks of the slaves, to compute the 
  37.  * network average delta, and to send to the slaves the differences between 
  38.  * their individual deltas and the network delta.
  39.  * While waiting, it receives messages from the slaves (i.e. requests for
  40.  * master's name, remote requests to set the network time, ...), and
  41.  * takes the appropriate action.
  42.  */
  43.  
  44. master()
  45. {
  46.     int ind;
  47.     long pollingtime;
  48.     struct timeval wait;
  49.     struct timeval time;
  50.     struct timeval otime;
  51.     struct timezone tzone;
  52.     struct tsp *msg, to;
  53.     struct sockaddr_in saveaddr;
  54.     int findhost();
  55.     char *date();
  56.     struct tsp *readmsg();
  57.     struct tsp *answer, *acksend();
  58.     char olddate[32];
  59.     struct sockaddr_in server;
  60.     register struct netinfo *ntp;
  61.  
  62. #ifdef MEASURE
  63.     if (fp == NULL) {
  64.         fp = fopen("/usr/adm/timed.masterlog", "w");
  65.         setlinebuf(fp);
  66.     }
  67. #endif
  68.  
  69.     syslog(LOG_INFO, "This machine is master");
  70.     if (trace)
  71.         fprintf(fd, "THIS MACHINE IS MASTER\n");
  72.  
  73.     for (ntp = nettab; ntp != NULL; ntp = ntp->next)
  74.         if (ntp->status == MASTER)
  75.             masterup(ntp);
  76.     pollingtime = 0;
  77.  
  78. loop:
  79.     (void)gettimeofday(&time, (struct timezone *)0);
  80.     if (time.tv_sec >= pollingtime) {
  81.         pollingtime = time.tv_sec + SAMPLEINTVL;
  82.         synch(0L);
  83.  
  84.         for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
  85.             to.tsp_type = TSP_LOOP;
  86.             to.tsp_vers = TSPVERSION;
  87.             to.tsp_seq = sequence++;
  88.             to.tsp_hopcnt = 10;
  89.             (void)strcpy(to.tsp_name, hostname);
  90.             bytenetorder(&to);
  91.             if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
  92.                 &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
  93.                 syslog(LOG_ERR, "sendto: %m");
  94.                 exit(1);
  95.             }
  96.         }
  97.     }
  98.  
  99.     wait.tv_sec = pollingtime - time.tv_sec;
  100.     wait.tv_usec = 0;
  101.     msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
  102.     if (msg != NULL) {
  103.         switch (msg->tsp_type) {
  104.  
  105.         case TSP_MASTERREQ:
  106.             break;
  107.         case TSP_SLAVEUP:
  108.             ind = addmach(msg->tsp_name, &from);
  109.             newslave(ind, msg->tsp_seq);
  110.             break;
  111.         case TSP_SETDATE:
  112.             saveaddr = from;
  113.             /*
  114.              * the following line is necessary due to syslog
  115.              * calling ctime() which clobbers the static buffer
  116.              */
  117.             (void)strcpy(olddate, date());
  118.             (void)gettimeofday(&time, &tzone);
  119.             otime = time;
  120.             time.tv_sec = msg->tsp_time.tv_sec;
  121.             time.tv_usec = msg->tsp_time.tv_usec;
  122.             (void)settimeofday(&time, &tzone);
  123.             syslog(LOG_NOTICE, "date changed from: %s", olddate);
  124.             logwtmp(otime, time);
  125.             msg->tsp_type = TSP_DATEACK;
  126.             msg->tsp_vers = TSPVERSION;
  127.             (void)strcpy(msg->tsp_name, hostname);
  128.             bytenetorder(msg);
  129.             if (sendto(sock, (char *)msg, sizeof(struct tsp), 0,
  130.                 &saveaddr, sizeof(struct sockaddr_in)) < 0) {
  131.                 syslog(LOG_ERR, "sendto: %m");
  132.                 exit(1);
  133.             }
  134.             spreadtime();
  135.             pollingtime = 0;
  136.             break;
  137.         case TSP_SETDATEREQ:
  138.             ind = findhost(msg->tsp_name);
  139.             if (ind < 0) { 
  140.                 syslog(LOG_WARNING,
  141.                 "DATEREQ from uncontrolled machine");
  142.                 break;
  143.             }
  144.             if (hp[ind].seq !=  msg->tsp_seq) {
  145.                 hp[ind].seq = msg->tsp_seq;
  146.                 /*
  147.                  * the following line is necessary due to syslog
  148.                  * calling ctime() which clobbers the static buffer
  149.                  */
  150.                 (void)strcpy(olddate, date());
  151.                 (void)gettimeofday(&time, &tzone);
  152.                 otime = time;
  153.                 time.tv_sec = msg->tsp_time.tv_sec;
  154.                 time.tv_usec = msg->tsp_time.tv_usec;
  155.                 (void)settimeofday(&time, &tzone);
  156.                 syslog(LOG_NOTICE,
  157.                     "date changed by %s from: %s",
  158.                     msg->tsp_name, olddate);
  159.                 logwtmp(otime, time);
  160.                 spreadtime();
  161.                 pollingtime = 0;
  162.             }
  163.             break;
  164.         case TSP_MSITE:
  165.         case TSP_MSITEREQ:
  166.             break;
  167.         case TSP_TRACEON:
  168.             if (!(trace)) {
  169.                 fd = fopen(tracefile, "w");
  170.                 setlinebuf(fd);
  171.                 fprintf(fd, "Tracing started on: %s\n\n", 
  172.                             date());
  173.             }
  174.             trace = ON;
  175.             break;
  176.         case TSP_TRACEOFF:
  177.             if (trace) {
  178.                 fprintf(fd, "Tracing ended on: %s\n", date());
  179.                 (void)fclose(fd);
  180.             }
  181. #ifdef GPROF
  182.             moncontrol(0);
  183.             _mcleanup();
  184.             moncontrol(1);
  185. #endif
  186.             trace = OFF;
  187.             break;
  188.         case TSP_ELECTION:
  189.             to.tsp_type = TSP_QUIT;
  190.             (void)strcpy(to.tsp_name, hostname);
  191.             server = from;
  192.             answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
  193.                 (struct netinfo *)NULL);
  194.             if (answer == NULL) {
  195.                 syslog(LOG_ERR, "election error");
  196.             } else {
  197.                 (void) addmach(msg->tsp_name, &from);
  198.             }
  199.             pollingtime = 0;
  200.             break;
  201.         case TSP_CONFLICT:
  202.             /*
  203.              * After a network partition, there can be 
  204.              * more than one master: the first slave to 
  205.              * come up will notify here the situation.
  206.              */
  207.  
  208.             (void)strcpy(to.tsp_name, hostname);
  209.  
  210.             if (fromnet == NULL)
  211.                 break;
  212.             for(;;) {
  213.                 to.tsp_type = TSP_RESOLVE;
  214.                 answer = acksend(&to, &fromnet->dest_addr,
  215.                     (char *)ANYADDR, TSP_MASTERACK, fromnet);
  216.                 if (answer == NULL)
  217.                     break;
  218.                 to.tsp_type = TSP_QUIT;
  219.                 server = from;
  220.                 msg = acksend(&to, &server, answer->tsp_name,
  221.                     TSP_ACK, (struct netinfo *)NULL);
  222.                 if (msg == NULL) {
  223.                     syslog(LOG_ERR, "error on sending QUIT");
  224.                 } else {
  225.                     (void) addmach(answer->tsp_name, &from);
  226.                 }
  227.             }
  228.             masterup(fromnet);
  229.             pollingtime = 0;
  230.             break;
  231.         case TSP_RESOLVE:
  232.             /*
  233.              * do not want to call synch() while waiting
  234.              * to be killed!
  235.              */
  236.             (void)gettimeofday(&time, (struct timezone *)0);
  237.             pollingtime = time.tv_sec + SAMPLEINTVL;
  238.             break;
  239.         case TSP_QUIT:
  240.             /* become slave */
  241. #ifdef MEASURE
  242.             if (fp != NULL) {
  243.                 (void)fclose(fp);
  244.                 fp = NULL;
  245.             }
  246. #endif
  247.             longjmp(jmpenv, 2);
  248.             break;
  249.         case TSP_LOOP:
  250.             /*
  251.              * We should not have received this from a net
  252.              * we are master on.  There must be two masters
  253.              * in this case.
  254.              */
  255.             to.tsp_type = TSP_QUIT;
  256.             (void)strcpy(to.tsp_name, hostname);
  257.             server = from;
  258.             answer = acksend(&to, &server, msg->tsp_name, TSP_ACK,
  259.                 (struct netinfo *)NULL);
  260.             if (answer == NULL) {
  261.                 syslog(LOG_WARNING,
  262.                     "loop breakage: no reply to QUIT");
  263.             } else {
  264.                 (void)addmach(msg->tsp_name, &from);
  265.             }
  266.         default:
  267.             if (trace) {
  268.                 fprintf(fd, "garbage: ");
  269.                 print(msg, &from);
  270.             }
  271.             break;
  272.         }
  273.     }
  274.     goto loop;
  275. }
  276.  
  277. /*
  278.  * `synch' synchronizes all the slaves by calling measure, 
  279.  * networkdelta and correct 
  280.  */
  281.  
  282. synch(mydelta)
  283. long mydelta;
  284. {
  285.     int i;
  286.     int measure_status;
  287.     long netdelta;
  288.     struct timeval tack;
  289. #ifdef MEASURE
  290. #define MAXLINES    8
  291.     static int lines = 1;
  292.     struct timeval start, end;
  293. #endif
  294.     int measure();
  295.     int correct();
  296.     long networkdelta();
  297.     char *date();
  298.  
  299.     if (slvcount > 1) {
  300. #ifdef MEASURE
  301.         (void)gettimeofday(&start, (struct timezone *)0);
  302.         if (header == ON || --lines == 0) {
  303.             fprintf(fp, "%s\n", date());
  304.             for (i=0; i<slvcount; i++)
  305.                 fprintf(fp, "%.7s\t", hp[i].name);
  306.             fprintf(fp, "\n");
  307.             lines = MAXLINES;
  308.             header = OFF;
  309.         }
  310. #endif
  311.         machup = 1;
  312.         hp[0].delta = 0;
  313.         for(i=1; i<slvcount; i++) {
  314.             tack.tv_sec = 0;
  315.             tack.tv_usec = 500000;
  316.             if ((measure_status = measure(&tack, &hp[i].addr)) <0) {
  317.                 syslog(LOG_ERR, "measure: %m");
  318.                 exit(1);
  319.             }
  320.             hp[i].delta = measure_delta;
  321.             if (measure_status == GOOD)
  322.                 machup++;
  323.         }
  324.         if (status & SLAVE) {
  325.             /* called by a submaster */
  326.             if (trace)
  327.                 fprintf(fd, "submaster correct: %d ms.\n",
  328.                     mydelta);
  329.             correct(mydelta);    
  330.         } else {
  331.             if (machup > 1) {
  332.                 netdelta = networkdelta();
  333.                 if (trace)
  334.                     fprintf(fd,
  335.                         "master correct: %d ms.\n",
  336.                         mydelta);
  337.                 correct(netdelta);
  338.             }
  339.         }
  340. #ifdef MEASURE
  341.         gettimeofday(&end, 0);
  342.         end.tv_sec -= start.tv_sec;
  343.         end.tv_usec -= start.tv_usec;
  344.         if (end.tv_usec < 0) {
  345.             end.tv_sec -= 1;
  346.             end.tv_usec += 1000000;
  347.         }
  348.         fprintf(fp, "%d ms.\n", (end.tv_sec*1000+end.tv_usec/1000));
  349. #endif
  350.         for(i=1; i<slvcount; i++) {
  351.             if (hp[i].delta == HOSTDOWN) {
  352.                 rmmach(i);
  353. #ifdef MEASURE
  354.                 header = ON;
  355. #endif
  356.             }
  357.         }
  358.     } else {
  359.         if (status & SLAVE) {
  360.             correct(mydelta);
  361.         }
  362.     }
  363. }
  364.  
  365. /*
  366.  * 'spreadtime' sends the time to each slave after the master
  367.  * has received the command to set the network time 
  368.  */
  369.  
  370. spreadtime()
  371. {
  372.     int i;
  373.     struct tsp to;
  374.     struct tsp *answer, *acksend();
  375.  
  376.     for(i=1; i<slvcount; i++) {
  377.         to.tsp_type = TSP_SETTIME;
  378.         (void)strcpy(to.tsp_name, hostname);
  379.         (void)gettimeofday(&to.tsp_time, (struct timezone *)0);
  380.         answer = acksend(&to, &hp[i].addr, hp[i].name, TSP_ACK,
  381.             (struct netinfo *)NULL);
  382.         if (answer == NULL) {
  383.             syslog(LOG_WARNING,
  384.                 "no reply to SETTIME from: %s", hp[i].name);
  385.         }
  386.     }
  387. }
  388.  
  389. findhost(name)
  390. char *name;
  391. {
  392.     int i;
  393.     int ind;
  394.  
  395.     ind = -1;
  396.     for (i=1; i<slvcount; i++) {
  397.         if (strcmp(name, hp[i].name) == 0) {
  398.             ind = i;
  399.             break;
  400.         }
  401.     }
  402.     return(ind);
  403. }
  404.  
  405. /*
  406.  * 'addmach' adds a host to the list of controlled machines
  407.  * if not already there 
  408.  */
  409.  
  410. addmach(name, addr)
  411. char *name;
  412. struct sockaddr_in *addr;
  413. {
  414.     int ret;
  415.     int findhost();
  416.  
  417.     ret = findhost(name);
  418.     if (ret < 0) {
  419.         hp[slvcount].addr = *addr;
  420.         hp[slvcount].name = (char *)malloc(MAXHOSTNAMELEN);
  421.         (void)strcpy(hp[slvcount].name, name);
  422.         hp[slvcount].seq = 0;
  423.         ret = slvcount;
  424.         if (slvcount < NHOSTS)
  425.             slvcount++;
  426.         else {
  427.             syslog(LOG_ERR, "no more slots in host table");
  428.         }
  429.     } else {
  430.         /* need to clear sequence number anyhow */
  431.         hp[ret].seq = 0;
  432.     }
  433. #ifdef MEASURE
  434.     header = ON;
  435. #endif
  436.     return(ret);
  437. }
  438.  
  439. /*
  440.  * Remove all the machines from the host table that exist on the given
  441.  * network.  This is called when a master transitions to a slave on a
  442.  * given network.
  443.  */
  444.  
  445. rmnetmachs(ntp)
  446.     register struct netinfo *ntp;
  447. {
  448.     int i;
  449.  
  450.     if (trace)
  451.         prthp();
  452.     for (i = 1; i < slvcount; i++)
  453.         if ((hp[i].addr.sin_addr.s_addr & ntp->mask) == ntp->net)
  454.             rmmach(i--);
  455.     if (trace)
  456.         prthp();
  457. }
  458.  
  459. /*
  460.  * remove the machine with the given index in the host table.
  461.  */
  462. rmmach(ind)
  463.     int ind;
  464. {
  465.     if (trace)
  466.         fprintf(fd, "rmmach: %s\n", hp[ind].name);
  467.     free(hp[ind].name);
  468.     hp[ind] = hp[--slvcount];
  469. }
  470.  
  471. prthp()
  472. {
  473.     int i;
  474.  
  475.     fprintf(fd, "host table:");
  476.     for (i=1; i<slvcount; i++)
  477.         fprintf(fd, " %s", hp[i].name);
  478.     fprintf(fd, "\n");
  479. }
  480.  
  481. masterup(net)
  482. struct netinfo *net;
  483. {
  484.     struct timeval wait;
  485.     struct tsp to, *msg, *readmsg();
  486.  
  487.     to.tsp_type = TSP_MASTERUP;
  488.     to.tsp_vers = TSPVERSION;
  489.     (void)strcpy(to.tsp_name, hostname);
  490.     bytenetorder(&to);
  491.     if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, &net->dest_addr,
  492.         sizeof(struct sockaddr_in)) < 0) {
  493.         syslog(LOG_ERR, "sendto: %m");
  494.         exit(1);
  495.     }
  496.  
  497.     for (;;) {
  498.         wait.tv_sec = 1;
  499.         wait.tv_usec = 0;
  500.         msg = readmsg(TSP_SLAVEUP, (char *)ANYADDR, &wait, net);
  501.         if (msg != NULL) {
  502.             (void) addmach(msg->tsp_name, &from);
  503.         } else
  504.             break;
  505.     }
  506. }
  507.  
  508. newslave(ind, seq)
  509. u_short seq;
  510. {
  511.     struct tsp to;
  512.     struct tsp *answer, *acksend();
  513.  
  514.     if (trace)
  515.         prthp();
  516.     if (seq == 0 || hp[ind].seq !=  seq) {
  517.         hp[ind].seq = seq;
  518.         to.tsp_type = TSP_SETTIME;
  519.         (void)strcpy(to.tsp_name, hostname);
  520.         /*
  521.          * give the upcoming slave the time
  522.          * to check its input queue before
  523.          * setting the time
  524.          */
  525.         sleep(1);
  526.         (void) gettimeofday(&to.tsp_time,
  527.             (struct timezone *)0);
  528.         answer = acksend(&to, &hp[ind].addr,
  529.             hp[ind].name, TSP_ACK,
  530.             (struct netinfo *)NULL);
  531.         if (answer == NULL) {
  532.             syslog(LOG_WARNING,
  533.                 "no reply to initial SETTIME from: %s",
  534.                 hp[ind].name);
  535.             rmmach(ind);
  536.         }
  537.     }
  538. }
  539.  
  540. char *wtmpfile = "/usr/adm/wtmp";
  541. struct utmp wtmp[2] = {
  542.     { "|", "", "", 0 },
  543.     { "{", "", "", 0 }
  544. };
  545.  
  546. logwtmp(otime, ntime)
  547. struct timeval otime, ntime;
  548. {
  549.     int f;
  550.  
  551.     wtmp[0].ut_time = otime.tv_sec + (otime.tv_usec + 500000) / 1000000;
  552.     wtmp[1].ut_time = ntime.tv_sec + (ntime.tv_usec + 500000) / 1000000;
  553.     if (wtmp[0].ut_time == wtmp[1].ut_time)
  554.         return;
  555.     if ((f = open(wtmpfile, O_WRONLY|O_APPEND)) >= 0) {
  556.         (void) write(f, (char *)wtmp, sizeof(wtmp));
  557.         (void) close(f);
  558.     }
  559. }
  560.